/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2021-2023. All rights reserved.
 *
 */

import path from 'path';

import { TaskDetails } from '@ohos/hvigor';

import { RestoolCommandBuilder } from '../../builder/restool-command-builder.js';
import { RestoolConfigBuilder } from '../../builder/restool-file-config-builder.js';
import { BuildDirConst, ResToolInputTypeConst } from '../../const/build-directory-const.js';
import { CoreModuleModelImpl } from '../../model/module/core-module-model-impl.js';
import { ModuleBuildProfile } from '../../options/build/module-build-profile.js';
import { Dependency } from '../../project/dependency/core/dependency-interface.js';
import { CompileResourcesUtil } from '../../utils/compile-resources-util.js';
import { FileUtil } from '../../utils/file-util.js';
import { HarTargetUtil } from '../../utils/har-target-util.js';
import { getJson5Obj } from '../../utils/json-util.js';
import { OhosLogger } from '../../utils/log/ohos-logger.js';
import { TargetTaskService } from '../service/target-task-service.js';
import { OhosHapTask } from '../task/ohos-hap-task.js';
import { OhPackageJsonOpt } from '../task/ohos-har-task.js';

const _log = OhosLogger.getLogger('Resource');

export abstract class AbstractResource extends OhosHapTask {
  restoolConfigBuilder: RestoolConfigBuilder;
  restoolCommandBuilder?: RestoolCommandBuilder;
  protected outputDir: string;

  protected constructor(taskService: TargetTaskService, taskDetails: TaskDetails) {
    super(taskService, taskDetails);
    this.outputDir = this.pathInfo.getIntermediatesRes();
    this.restoolConfigBuilder = this.getRestoolConfigBuilder();
  }

  /**
   * get common restool config builder
   *
   * @returns {RestoolBuilderInterface} resTool命令构造器
   */
  protected getRestoolConfigBuilder(): RestoolConfigBuilder {
    const restoolBuilder = this.initConfigTargetResource();
    const restoolModuleNames = CompileResourcesUtil.getRestoolModuleNames(this.service, this.targetName).join(',');

    _log.debug(`restool module names: ${restoolModuleNames}; moduleName=${this.moduleName}, taskName=${this.name}`);
    restoolBuilder.addModules(restoolModuleNames).forceDelete();

    // 加入har依赖中的resources
    const harResourceMap = new Map<string, string[] | string>();

    this.getHarPathToResourcesDirMap(harResourceMap);

    harResourceMap.set(this.pathInfo.getModulePath(), this.pathInfo.getResourceStr());
    harResourceMap.forEach((value) => {
      if (Array.isArray(value)) {
        value.forEach((resourcePath) => {
          restoolBuilder.addInputDir(resourcePath, ResToolInputTypeConst.HAR);
        });
      } else {
        restoolBuilder.addInputDir(value, ResToolInputTypeConst.HAR);
      }
    });
    return restoolBuilder;
  }

  /**
   * get common restool command builder
   *
   * @returns {RestoolBuilderInterface} resTool编译、链接命令构造器
   * @protected
   */
  protected initConfigTargetResource(): RestoolConfigBuilder {
    const restoolBuilder = new RestoolConfigBuilder();
    const resourceDirs: string[] = this.targetService.getResourceDirs();
    resourceDirs.forEach((dir) => restoolBuilder.addInputDir(dir, 'Module'));
    return restoolBuilder;
  }

  protected getRestoolCommandBuilder(): RestoolCommandBuilder {
    const restoolBuilder = this.initCommandTargetResource();
    restoolBuilder.addModules(CompileResourcesUtil.getRestoolModuleNames(this.service, this.targetName).join(',')).forceDelete();
    return restoolBuilder;
  }

  protected initCommandTargetResource(): RestoolCommandBuilder {
    const restoolBuilder = new RestoolCommandBuilder(this.sdkInfo.getRestool());

    // kv映射 key为resourcePath，value为restool编译中间文件夹名称
    const moduleResourcesMap = new Map<string, string>();
    const harResourcesMap = new Map<string, string>();

    const resourceDirs: string[] = this.targetService.getResourceDirs();
    resourceDirs.forEach((dir, index) => {
      const compileDirName = CompileResourcesUtil.getCompileTargetFolderBySeq(BuildDirConst.MODULE_COMPILED, index);
      moduleResourcesMap.set(dir, compileDirName);
    });

    // 加入har依赖中的resources
    const harPathToResourcesDirMap = new Map<string, string[] | string>();
    const harResourcesPaths :string[] = [];

    this.getHarPathToResourcesDirMap(harPathToResourcesDirMap);

    harPathToResourcesDirMap.forEach((value) => {
      if (Array.isArray(value)) {
        value.forEach((resourcePath) => {
          harResourcesPaths.push(resourcePath);
        });
      } else {
        harResourcesPaths.push(value);
      }
    });

    harResourcesPaths.forEach((harPath, seq) => {
      const compileDirName = CompileResourcesUtil.getCompileTargetFolderBySeq(BuildDirConst.HAR_COMPILED, seq);
      harResourcesMap.set(harPath, compileDirName);
    });

    restoolBuilder.addModuleResourcesMap(moduleResourcesMap);
    restoolBuilder.addHarResourcesMap(harResourcesMap);

    return restoolBuilder;
  }

  /**
   * 获取Har资源的Map，包括local har和三方库的资源，需要根据用户对应target配置的resources来取
   * @param harResourceMap 用于存储Har资源的映射 <dependency path, resource dir / [resource dir]>
   */
  private getHarPathToResourcesDirMap(harResourceMap: Map<string, string[] | string>) {
    // 处理本地依赖,使用target中的resource目录
    const depHarTargets = HarTargetUtil.calDepHarTargets(this.targetService);
    depHarTargets.forEach((targetName, harName) => {
      const harModule = <CoreModuleModelImpl>this.projectModel.getModuleModelByName(harName);
      if (harModule === undefined) {
        return;
      }
      const harBuildProfileJsonOpt: ModuleBuildProfile.ModuleBuildOpt = harModule.getProfileOpt();
      if (harBuildProfileJsonOpt?.targets?.length) {
        const harTarget = harBuildProfileJsonOpt.targets.find((harTargetName) => harTargetName.name === targetName);
        if (harTarget?.resource?.directories?.length) {
          harResourceMap.set(harModule.getProjectDir(), FileUtil.convertToAbsolutePaths(harTarget.resource.directories, harModule.getProjectDir()));
        }
      }
    });

    // 处理三方依赖
    this.service.getHarDependencies().forEach((dependency) => {
      if (harResourceMap.has(dependency.getDependencyRootPath())) {
        return;
      }
      const packageObj: OhPackageJsonOpt = getJson5Obj(dependency.getPackageFilePath(), 'utf-8');
      if (packageObj?.metadata?.resource?.directories?.length) {
        harResourceMap.set(
          dependency.getDependencyRootPath(),
          FileUtil.convertToAbsolutePaths(packageObj.metadata.resource.directories, dependency.getDependencyRootPath()),
        );
      } else {
        harResourceMap.set(
          dependency.getDependencyRootPath(),
          path.resolve(dependency.getDependencyRootPath(), BuildDirConst.SRC, BuildDirConst.MAIN, BuildDirConst.RESTOOL_BUILD_RESOURCES),
        );
      }
    });
  }
}
